<template>
  <div id="app">
    <div ref="container"
         class="container"
         :style="containerStyle"
         @scroll="onScroll">
      <div class="wrapper"
           :style="wrapperStyle">
        <!-- <div v-for="ele in list" :key="ele.index" class="content">
          Row: {{ ele.data }}
        </div> -->
        <ul border="1"
            class="header_father">
          <li class="header">
            <th v-for="item in Object.keys(valueList[0])"
                :key="item">{{item}}</th>
          </li>
          <li v-for="(item) in list"
              :key="item.index"
              class="content">
            <span>{{item.index}}</span>
            <span>{{item.data.id}}</span>
            <span>{{item.natureName}}</span>
            <span>{{item.penaltyMoney}}</span>
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script>
/**
 * 模型简化 弹窗
 * @description
 * @property {Boolean}        visible         显示弹窗
 * @property {String}         title           标题
 * @property {String|Number}  width           弹窗宽度(默认'363px')
 * @property {String|Number}  height          弹窗高度(默认auto)
 * @event    {Function}       cancel          关闭弹窗触发，当前组件为右上角x号
 */
export default {
  name: 'QTable',
  props: {
    visibleData: {
      // 数组-数据
      type: Array,
      default: () => []
    },
    height: {
      type: String,
      default: '600'
    }
  },
  data () {
    return {
      // valueList: [],
      valueList: this.visibleData,
      start: 0,
      end: 10,
      itemHeight: 80, // 元素高度
      overscan: 3 // 多渲染数

    }
  },
  computed: {
    list () {
      // 实际渲染数量
      const valueList = this.valueList
      const start = this.start
      const end = this.end
      return valueList.slice(start, end).map((item, index) => {
        return {
          data: item,
          index: index + start
        }
      })
    },
    totalHeight () {
      // 元素总高度
      const that = this
      return that.list.length * that.itemHeight
    },
    offsetTop () {
      // 距顶部的距离
      return this.start * this.itemHeight
    },
    containerStyle () {
      // 外层样式
      return {
        overflowY: 'auto',
        height: this.height + 'px'
      }
    },
    wrapperStyle () {
      // 列表包裹样式
      return {
        width: '100%',
        paddingTop: this.offsetTop + 'px'
      }
    }
  },
  methods: {
    getOffset (scrollTop) {
      // 滚动到可见区域外的元素数量
      return Math.floor(scrollTop / this.itemHeight) + 1
    },
    getViewCapacity (containerHeight) {
      // 可见区域内能显示的数量
      return Math.ceil(containerHeight / this.itemHeight)
    },
    calculateRange () {
      // 计算实际渲染数据
      const that = this
      const element = that.$refs.container
      if (element) {
        const offset = that.getOffset(element.scrollTop)
        const viewCapacity = that.getViewCapacity(element.clientHeight)
        const overscan = that.overscan
        const list = that.valueList
        // 重新计算开始，滚动到到显示区域外的数量，减去预渲染数量,最小值为0
        const from = offset - overscan
        const start = from < 0 ? 0 : from
        // 重新计算结束，最大值为实际数据列表的长度
        const to = offset + viewCapacity + overscan
        const end = to > list.length ? list.length : to
        // 滚动到最后了，可以做增加原始数据的操作等
        if (to === overscan + list.length + 1) {
          const scrollBottom = that.scrollBottom
          scrollBottom && scrollBottom()
        }
        that.start = start
        that.end = end
      }
    },
    onScroll (e) {
      e.preventDefault()
      this.calculateRange()
    },
    scrollTo (index) {
      const element = this.$refs.container
      if (element) {
        element.scrollTop = index * this.itemHeight
        this.calculateRange()
      }
    }
  }
}
</script>

<style lang="scss" scoped>
#app {
  position: relative;
  .container {
    .wrapper {
      .header_father {
        .header {
          position: absolute;
          top: 0;
        }
      }

      .content {
        background-color: skyblue;
        height: 72px;
        border: 1px solid #e8e8e8;
        margin-bottom: 8px;
      }
    }
  }
}
</style>
